﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
using MahApps.Metro.Controls;
using Encoder = System.Drawing.Imaging.Encoder;

namespace JY.Wpf.TestClient.Commons
{
    /// <summary>
    /// 图片工具
    /// </summary>
    public static class ImageTools
    {
        #region # 注销对象方法API——int DeleteObject(IntPtr o)
        /// <summary>
        /// 注销对象方法API
        /// </summary>
        [DllImport("gdi32")]
        static extern int DeleteObject(IntPtr o);
        #endregion

        #region # 转换Bitmap为BitmapSource——BitmapSource ConvertBitmapToBitmapSource(Bitmap bitmap)
        /// <summary>
        /// 转换Bitmap为BitmapSource
        /// </summary>
        /// <param name="bitmap">图片Bitmap</param>
        public static BitmapSource ConvertBitmapToBitmapSource(Bitmap bitmap, long? compressLevel = 60)
        {
            if (compressLevel != null)
            {
                using (var compressBitmap = new Bitmap(Compress(bitmap, compressLevel.Value)))
                {
                    var hBitmap = compressBitmap.GetHbitmap();
                    BitmapSource bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
                    bitmapSource.Freeze();
                    DeleteObject(hBitmap);
                    return bitmapSource;
                }
            }
            else
            {
                using (var compressBitmap = (Bitmap)bitmap.Clone())
                {
                    var hBitmap = compressBitmap.GetHbitmap();
                    BitmapSource bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
                    bitmapSource.Freeze();
                    DeleteObject(hBitmap);
                    return bitmapSource;
                }
            }
        }
        #endregion

        #region # 转换Bitmap为BitmapImage ——BitmapImage ConvertBitmapToToBitmapImage(Bitmap bitmap)
        /// <summary>
        /// 转换Bitmap为BitmapImage
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        public static BitmapImage ConvertBitmapToToBitmapImage(Bitmap bitmap)
        {
            BitmapImage bitmapImage = new BitmapImage();
            bitmapImage.BeginInit();
            MemoryStream memoryStream = new MemoryStream();
            bitmap.Save(memoryStream, ImageFormat.Bmp);
            memoryStream.Seek(0, SeekOrigin.Begin);
            bitmapImage.StreamSource = memoryStream;
            bitmapImage.EndInit();
            bitmapImage.Freeze();
            return bitmapImage;
        }
        #endregion

        #region # 根据图片路径读取图片BitmapSource——BitmapSource ReadImage(string imagePath)
        /// <summary>
        /// 根据图片路径读取图片BitmapSource
        /// </summary>
        /// <param name="imagePath">图片路径</param>
        public static BitmapSource ReadImage(string imagePath)
        {
            if (File.Exists(imagePath))
            {
                BitmapImage bitmapImage = new BitmapImage();
                using (Stream memoryStream = new MemoryStream(File.ReadAllBytes(imagePath)))
                {
                    bitmapImage.BeginInit();
                    bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                    bitmapImage.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
                    bitmapImage.StreamSource = memoryStream;
                    bitmapImage.EndInit();
                    bitmapImage.Freeze();
                }
                return bitmapImage;
            }
            else
            {
                return null;
            }
        }
        #endregion

        #region # 根据图片路径读取图片Bitmap——Bitmap ReadBitmap(string imagePath)
        /// <summary>
        /// 根据图片路径读取图片Bitmap
        /// </summary>
        /// <param name="imagePath">图片路径</param>
        public static Bitmap ReadBitmap(string imagePath)
        {
            if (File.Exists(imagePath))
            {
                Bitmap bitmap;
                using (Stream memoryStream = new MemoryStream(File.ReadAllBytes(imagePath)))
                {
                    bitmap = new Bitmap(memoryStream);
                }
                return bitmap;
            }
            else
            {
                return null;
            }
        }
        #endregion

        #region # 写入Bitmap到文件——void WriteBitmapToFile(Bitmap bitmap, string absolutePath, ImageFormat imageFormat, bool isCompress = true)
        /// <summary>
        /// 写入Bitmap到文件
        /// </summary>
        /// <param name="bitmap">bitmap</param>
        /// <param name="absolutePath">文件路径</param>
        /// <param name="imageFormat">图片格式</param>
        /// <param name="isCompress">是否压缩</param>
        public static async void WriteBitmapToFile(Bitmap bitmap, string absolutePath, ImageFormat imageFormat, bool isCompress = true)
        {
            if (isCompress)
            {
                Stream stream = Compress(bitmap, 60);
                stream.Seek(0, SeekOrigin.Begin);

                using (var fileStream = new FileStream(absolutePath, FileMode.OpenOrCreate))
                {
                    await stream.CopyToAsync(fileStream);
                }
            }
            else
            {
                var directoryName = Path.GetDirectoryName(absolutePath);
                if (!Directory.Exists(directoryName))
                {
                    Directory.CreateDirectory(directoryName);
                }
                bitmap.Save(absolutePath, ImageFormat.Bmp);
            }
        }
        #endregion

        #region # 图片压缩(降低质量以减小文件的大小)——Stream Compress(Bitmap srcBitmap, long level)
        /// <summary>
        /// 图片压缩(降低质量以减小文件的大小)
        /// </summary>
        /// <param name="srcBitmap">传入的Bitmap对象</param>
        /// <param name="level">压缩等级，0到100，0 最差质量，100 最佳</param>
        public static Stream Compress(Bitmap srcBitmap, long level)
        {
            ImageCodecInfo myImageCodecInfo;
            System.Drawing.Imaging.Encoder myEncoder;
            EncoderParameter myEncoderParameter;
            EncoderParameters myEncoderParameters;

            // Get an ImageCodecInfo object that represents the JPEG codec.
            myImageCodecInfo = GetEncoderInfo("image/jpeg");

            // Create an Encoder object based on the GUID

            // for the Quality parameter category.
            myEncoder = Encoder.Quality;

            // Create an EncoderParameters object.
            // An EncoderParameters object has an array of EncoderParameter
            // objects. In this case, there is only one

            // EncoderParameter object in the array.
            myEncoderParameters = new EncoderParameters(1);

            // Save the bitmap as a JPEG file with 给定的 quality level
            myEncoderParameter = new EncoderParameter(myEncoder, level);
            myEncoderParameters.Param[0] = myEncoderParameter;
            MemoryStream memoryStream = new MemoryStream();
            srcBitmap.Save(memoryStream, myImageCodecInfo, myEncoderParameters);
            return memoryStream;
        }
        private static ImageCodecInfo GetEncoderInfo(string mimeType)
        {
            int j;
            ImageCodecInfo[] encoders;
            encoders = ImageCodecInfo.GetImageEncoders();
            for (j = 0; j < encoders.Length; ++j)
            {
                if (encoders[j].MimeType == mimeType)
                    return encoders[j];
            }
            return null;
        }
        #endregion

        //水印相关
        #region # 图片水印——void AddImageSignPic(string imgPath...
        /// <summary>
        /// 图片水印
        /// </summary>
        /// <param name="imgPath">服务器图片相对路径</param>
        /// <param name="filename">保存文件名</param>
        /// <param name="watermarkFilename">水印文件相对路径</param>
        /// <param name="watermarkStatus">图片水印位置 0=不使用 1=左上 2=中上 3=右上 4=左中  9=右下</param>
        /// <param name="quality">附加水印图片质量,0-100</param>
        /// <param name="watermarkTransparency">水印的透明度 1--10 10为不透明</param>
        public static void AddImageSignPic(string imgPath, string filename, string watermarkFilename, int watermarkStatus, int quality, int watermarkTransparency)
        {
            if (!File.Exists(GetMapPath(imgPath)))
                return;
            byte[] imageBytes = File.ReadAllBytes(GetMapPath(imgPath));
            Image img = Image.FromStream(new System.IO.MemoryStream(imageBytes));
            filename = GetMapPath(filename);

            if (watermarkFilename.StartsWith("/") == false)
                watermarkFilename = "/" + watermarkFilename;
            watermarkFilename = GetMapPath(watermarkFilename);
            if (!File.Exists(watermarkFilename))
                return;
            Graphics g = Graphics.FromImage(img);
            //设置高质量插值法
            //g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
            //设置高质量,低速度呈现平滑程度
            //g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            Image watermark = new Bitmap(watermarkFilename);

            if (watermark.Height >= img.Height || watermark.Width >= img.Width)
                return;

            ImageAttributes imageAttributes = new ImageAttributes();
            ColorMap colorMap = new ColorMap();

            colorMap.OldColor = Color.FromArgb(255, 0, 255, 0);
            colorMap.NewColor = Color.FromArgb(0, 0, 0, 0);
            ColorMap[] remapTable = { colorMap };

            imageAttributes.SetRemapTable(remapTable, ColorAdjustType.Bitmap);

            float transparency = 0.5F;
            if (watermarkTransparency >= 1 && watermarkTransparency <= 10)
                transparency = (watermarkTransparency / 10.0F);


            float[][] colorMatrixElements = {
                                                new float[] {1.0f,  0.0f,  0.0f,  0.0f, 0.0f},
                                                new float[] {0.0f,  1.0f,  0.0f,  0.0f, 0.0f},
                                                new float[] {0.0f,  0.0f,  1.0f,  0.0f, 0.0f},
                                                new float[] {0.0f,  0.0f,  0.0f,  transparency, 0.0f},
                                                new float[] {0.0f,  0.0f,  0.0f,  0.0f, 1.0f}
                                            };

            ColorMatrix colorMatrix = new ColorMatrix(colorMatrixElements);

            imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

            int xpos = 0;
            int ypos = 0;

            switch (watermarkStatus)
            {
                case 1:
                    xpos = (int)(img.Width * (float).01);
                    ypos = (int)(img.Height * (float).01);
                    break;
                case 2:
                    xpos = (int)((img.Width * (float).50) - (watermark.Width / 2));
                    ypos = (int)(img.Height * (float).01);
                    break;
                case 3:
                    xpos = (int)((img.Width * (float).99) - (watermark.Width));
                    ypos = (int)(img.Height * (float).01);
                    break;
                case 4:
                    xpos = (int)(img.Width * (float).01);
                    ypos = (int)((img.Height * (float).50) - (watermark.Height / 2));
                    break;
                case 5:
                    xpos = (int)((img.Width * (float).50) - (watermark.Width / 2));
                    ypos = (int)((img.Height * (float).50) - (watermark.Height / 2));
                    break;
                case 6:
                    xpos = (int)((img.Width * (float).99) - (watermark.Width));
                    ypos = (int)((img.Height * (float).50) - (watermark.Height / 2));
                    break;
                case 7:
                    xpos = (int)(img.Width * (float).01);
                    ypos = (int)((img.Height * (float).99) - watermark.Height);
                    break;
                case 8:
                    xpos = (int)((img.Width * (float).50) - (watermark.Width / 2));
                    ypos = (int)((img.Height * (float).99) - watermark.Height);
                    break;
                case 9:
                    xpos = (int)((img.Width * (float).99) - (watermark.Width));
                    ypos = (int)((img.Height * (float).99) - watermark.Height);
                    break;
            }

            g.DrawImage(watermark, new Rectangle(xpos, ypos, watermark.Width, watermark.Height), 0, 0, watermark.Width, watermark.Height, GraphicsUnit.Pixel, imageAttributes);

            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
            ImageCodecInfo ici = null;
            foreach (ImageCodecInfo codec in codecs)
            {
                if (codec.MimeType.IndexOf("jpeg", StringComparison.Ordinal) > -1)
                    ici = codec;
            }
            EncoderParameters encoderParams = new EncoderParameters();
            long[] qualityParam = new long[1];
            if (quality < 0 || quality > 100)
                quality = 80;

            qualityParam[0] = quality;

            EncoderParameter encoderParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qualityParam);
            encoderParams.Param[0] = encoderParam;

            if (ici != null)
                img.Save(filename, ici, encoderParams);
            else
                img.Save(filename);

            g.Dispose();
            img.Dispose();
            watermark.Dispose();
            imageAttributes.Dispose();
        }
        #endregion

        #region # 文字水印——void AddImageSignText(string imgPath...
        /// <summary>
        /// 文字水印
        /// </summary>
        /// <param name="imgPath">服务器图片相对路径</param>
        /// <param name="filename">保存文件名</param>
        /// <param name="watermarkText">水印文字</param>
        /// <param name="watermarkStatus">图片水印位置 0=不使用 1=左上 2=中上 3=右上 4=左中  9=右下</param>
        /// <param name="quality">附加水印图片质量,0-100</param>
        /// <param name="fontsize">字体大小</param>
        /// <param name="fontColor">字体颜色</param>
        /// <param name="fontname">字体</param>
        public static void AddImageSignText(string imgPath, string filename, string watermarkText, int watermarkStatus, int quality, int fontsize, Color fontColor, string fontname = "微软雅黑")
        {
            byte[] imageBytes = File.ReadAllBytes(GetMapPath(imgPath));
            Image img = Image.FromStream(new System.IO.MemoryStream(imageBytes));
            filename = GetMapPath(filename);

            Graphics g = Graphics.FromImage(img);
            Font drawFont = new Font(fontname, fontsize, System.Drawing.FontStyle.Regular, GraphicsUnit.Pixel);
            SizeF crSize;
            crSize = g.MeasureString(watermarkText, drawFont);

            float xpos = 0;
            float ypos = 0;

            switch (watermarkStatus)
            {
                case 1:
                    xpos = (float)img.Width * (float).01;
                    ypos = (float)img.Height * (float).01;
                    break;
                case 2:
                    xpos = ((float)img.Width * (float).50) - (crSize.Width / 2);
                    ypos = (float)img.Height * (float).01;
                    break;
                case 3:
                    xpos = ((float)img.Width * (float).99) - crSize.Width;
                    ypos = (float)img.Height * (float).01;
                    break;
                case 4:
                    xpos = (float)img.Width * (float).01;
                    ypos = ((float)img.Height * (float).50) - (crSize.Height / 2);
                    break;
                case 5:
                    xpos = ((float)img.Width * (float).50) - (crSize.Width / 2);
                    ypos = ((float)img.Height * (float).50) - (crSize.Height / 2);
                    break;
                case 6:
                    xpos = ((float)img.Width * (float).99) - crSize.Width;
                    ypos = ((float)img.Height * (float).50) - (crSize.Height / 2);
                    break;
                case 7:
                    xpos = (float)img.Width * (float).01;
                    ypos = ((float)img.Height * (float).99) - crSize.Height;
                    break;
                case 8:
                    xpos = ((float)img.Width * (float).50) - (crSize.Width / 2);
                    ypos = ((float)img.Height * (float).99) - crSize.Height;
                    break;
                case 9:
                    xpos = ((float)img.Width * (float).99) - crSize.Width;
                    ypos = ((float)img.Height * (float).99) - crSize.Height;
                    break;
            }

            g.DrawString(watermarkText, drawFont, new SolidBrush(fontColor), xpos, ypos);

            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
            ImageCodecInfo ici = null;
            foreach (ImageCodecInfo codec in codecs)
            {
                if (codec.MimeType.IndexOf("jpeg") > -1)
                    ici = codec;
            }
            EncoderParameters encoderParams = new EncoderParameters();
            long[] qualityParam = new long[1];
            if (quality < 0 || quality > 100)
                quality = 80;

            qualityParam[0] = quality;

            EncoderParameter encoderParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qualityParam);
            encoderParams.Param[0] = encoderParam;

            if (ici != null)
                img.Save(filename, ici, encoderParams);
            else
                img.Save(filename);

            g.Dispose();
            img.Dispose();
        }
        #endregion

        #region # 文字水印——void ImageDrawWatermarkByText(Bitmap bitmap...
        /// <summary>
        /// 文字水印
        /// </summary>
        /// <param name="bitmap">图片</param>
        /// <param name="watermarkText">水印信息</param>
        /// <param name="fontSize">文字</param>
        /// <param name="fontName">字体名称</param>
        /// <param name="fontColor">字体颜色</param>
        /// <param name="fontStyle">字体样式</param>
        /// <param name="angle">旋转角度</param>
        public static void ImageDrawWatermarkByText(Bitmap bitmap, string watermarkText, Color fontColor, float fontSize = 60, string fontName = "微软雅黑", System.Drawing.FontStyle fontStyle = System.Drawing.FontStyle.Bold, float angle = 30)
        {
            if (bitmap == null) return;
            using (Graphics graphics = Graphics.FromImage(bitmap))
            {
                float imageWidth = (float)bitmap.Width;
                float imageHeight = (float)bitmap.Height;
                graphics.RotateTransform(angle);
                graphics.TranslateTransform(0, -imageHeight / 2);

                float fontPanelHeight = fontSize * 14;

                //设置旋转角度
                Font drawFont = new Font(fontName, fontSize, fontStyle, GraphicsUnit.Pixel);
                SizeF sizeF = graphics.MeasureString(watermarkText, drawFont);
                float xpos = 0;
                float ypos = 0;
                for (int i = 0; i < (imageHeight + imageHeight / 2) / fontPanelHeight; i++)
                {
                    xpos = 0;
                    ypos = fontPanelHeight * i - fontSize;
                    graphics.DrawString(watermarkText, drawFont, new SolidBrush(fontColor), xpos, ypos);

                    xpos = imageWidth / 2 - sizeF.Width / 2;
                    ypos = fontPanelHeight * i - fontSize;
                    graphics.DrawString(watermarkText, drawFont, new SolidBrush(fontColor), xpos, ypos);

                    xpos = imageWidth - sizeF.Width;
                    ypos = fontPanelHeight * i - fontSize;
                    graphics.DrawString(watermarkText, drawFont, new SolidBrush(fontColor), xpos, ypos);
                }
            }
        }
        #endregion

        #region # 获得当前绝对路径——string GetMapPath(string strPath)
        /// <summary>
        /// 获得当前绝对路径
        /// </summary>
        /// <param name="strPath">指定的路径</param>
        /// <returns>绝对路径</returns>
        public static string GetMapPath(string strPath)
        {
            if (strPath.ToLower().StartsWith("http://"))
            {
                return strPath;
            }
            if (HttpContext.Current != null)
            {
                return HttpContext.Current.Server.MapPath(strPath);
            }
            else //非web程序引用
            {
                strPath = strPath.Replace("/", "\\");
                if (strPath.StartsWith("\\"))
                {
                    strPath = strPath.Substring(strPath.IndexOf('\\', 1)).TrimStart('\\');
                }
                return System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, strPath);
            }
        }
        #endregion
    }
}
